#include <cstring>
#include "gamemap.hpp"
#include "piece.hpp"
#include "terminal.hpp"
#define Error(str) string(str __FILE__ " ") + to_string(__LINE__)

GameMap gameMap;

GameMap::GameMap(int r, int c):r(r),c(c){
	if (r < 0 || c < 0)
		Exception(Error("地图初始化错误"));
	ptr = new uint8_t[r * c];
	if (ptr == NULL){
		cerr << "运行空间不足" << endl;
		exit(-1);
	}
}

uint8_t *GameMap::operator[](int x){
	if (x > r || r < 0)
		throw Exception(Error("访问越界"));
	return ptr + x * c;
}

uint8_t &GameMap::operator[](const Coordinate &coor){
	if (coor.x < r && coor.x >= 0 && coor.y < c && coor.y >= 0)
		return *(ptr + coor.x * c + coor.y);
	else
		throw Exception(Error("访问越界"));
}

const uint8_t *GameMap::operator[](int x)const{
	if (x > r || r < 0)
		throw Exception(Error("访问越界"));
	return ptr + x * c;
}

uint8_t GameMap::operator[](const Coordinate &coor)const{
	if (coor.x < r && coor.x >= 0 && coor.y < c && coor.y >= 0)
		return *(ptr + coor.x * c + coor.y);
	else
		throw Exception(Error("访问越界"));
}

GameMap &GameMap::operator=(const GameMap &gm){
	if (ptr)
		delete[] ptr;
	r = gm.r;
	c = gm.c;
	ptr = new uint8_t[r * c];
	if (ptr == NULL){
		cerr << "运行空间不足" << endl;
		exit(-1);
	}
	for (int i = 0; i < r; ++i)
		for (int j = 0; j < c; ++j)
			ptr[i * c + j] = gm.ptr[i * c + j];
	return *this;
}

GameMap &GameMap::operator=(GameMap &&gm){
	if (ptr)
		delete[] ptr;
	r = gm.r;
	c = gm.c;
	ptr = gm.ptr;
	return *this;
}

uint8_t GameMap::queryCoor(int x, int y){
	if (x < r && x >= 0 && y < c && y >= 0)
		return *(ptr + x * c + y);
	else
		throw Exception(Error("访问越界"));
}

uint8_t GameMap::queryCoor(const Coordinate &coor){
	if (coor.x < r && coor.x >= 0 && coor.y < c && coor.y >= 0)
		return *(ptr + coor.x * c + coor.y);
	else
		throw Exception(Error("访问越界"));
}

GameMap::~GameMap(){
	if (ptr)
		delete[] ptr;
}

void GameMap::clear()noexcept{
	memset(ptr, 0, sizeof(uint8_t) * r * c);
}

void GameMap::present(ostream &os)noexcept{
	for (int i = 0; i < r; ++i){
		for (int j = 0; j < c; ++j){
			os << *pieces[ptr[i * c + j]];
		}
		os << endl;
	}
}
